﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ca2simulator.client.view.grid;
using ca2simulator.shared;
using ca2simulator.client.model.transfer;
using System.Threading;
using ca2simulator.client.model.transfer.generator;
using ca2simulator.shared.wcf;
using System.ServiceModel;
using ca2simulator.client.wcf;
using System.Windows.Threading;

namespace ca2simulator.client.view
{
    /// <summary>
    /// Interaction logic for LifeUserControl.xaml
    /// </summary>
    public partial class CAUserControl : UserControl
    {
        //TODO Udate with proxies
        private MySim _Sim;
        private LatticeRenderer _renderer;
        private Dispatcher _UIDispatcher;

        #region Fps counter variables
        private Timer _FpsTimer;
        private uint _renderFrameCount;
        private uint _simFrameCount;
        private double _simFps, _rendFps;
        private delegate void Update();
        private Update _FpsUpdate;
        #endregion

        public CAUserControl(CA2Raw ca)
        {
            InitializeComponent();
            _Sim = new MySim(ca);
            
            addButtonListeners();
            
            _renderer = new LatticeRenderer(new Lattice(ca.InitialLattice.InitialState, ca.InitialLattice.Rows, ca.InitialLattice.Columns), simImage);

            //_Sim.LatticeChanged += new MySim.LatticeChangedHandler(_Sim_LatticeChanged);
            _Sim.LatticeChanges += new MySim.LatticeChangesHandler(_Sim_LatticeChanges);

            // UI dispatcher so other threads can modify UI
            _UIDispatcher = Application.Current.Dispatcher;

            SetupTimer();

            // Create method to clean up when this is closed
            this.Unloaded += new RoutedEventHandler(delegate(object sender, RoutedEventArgs e)
            {
                if (_Sim != null) _Sim.Dispose();
                if (_renderer != null) _renderer.Dispose();
            });
        }

        void SetupTimer()
        {
            //renderer event to increment frame counter
            _renderer.UpdateComplete += new LatticeRenderer.UpdateCompleteHanlder(delegate(object sender)
            {
                _renderFrameCount++;
            });

            // Delegate to update gui labels
            _FpsUpdate = delegate()
            {
                label_simfps.Content = String.Format("{0:0.00}", _simFps);
                label_rendfps.Content = String.Format("{0:0.00}", _rendFps);
            };
            // timers to update fps member variables
            _FpsTimer = new Timer(delegate(object o)
            {
                //calculate fps using simple IIR
                _simFps = _simFps * 0.25 + _simFrameCount * 0.75;
                _simFrameCount = 0;
                _rendFps = _rendFps*0.25 + _renderFrameCount * 0.75;
                _renderFrameCount = 0;
                //display fps
                _UIDispatcher.BeginInvoke(_FpsUpdate);
            }
                , null, 0, 1000);
        }

        void _Sim_LatticeChanges(object sender, CellChange[] changes)
        {
            int count = changes.Length;
            CellChange change;
            Cell newCell;

            for (int i = 0; i < count; i++)
            {
                change = changes[i];
                newCell.CellState = change.State;
                _renderer.Lattice[change.Location.row, change.Location.col] = newCell;
            }
            _simFrameCount++;
            _renderer.InvokeUpdate();

            
        }

        void _Sim_LatticeChanged(object sender, Lattice data)
        {
            _renderer.Lattice = data;
            _renderer.InvokeUpdate();
        }

        void addButtonListeners()
        {
            RunButton.Click += new RoutedEventHandler(runButton_Click);
            StopButton.Click += new RoutedEventHandler(stopButton_Click);
            StepButton.Click += new RoutedEventHandler(stepButton_Click);
        }

        #region Button Click methods
        void runButton_Click(object sender, RoutedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(delegate(object o)
            {
                _Sim.Run();
            });
        }

        void stopButton_Click(object sender, RoutedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(delegate(object o)
           {
               _Sim.Halt();
           });
        }

        void stepButton_Click(object sender, RoutedEventArgs e)
        {
            ThreadPool.QueueUserWorkItem(delegate(object o)
           {
               _Sim.Step(1);
           });
        }
        #endregion

        private void slider_zoom_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (simImage != null && scrollViewer != null)
            {
                simImage.Height = scrollViewer.Height * slider_zoom.Value;
                simImage.Width = scrollViewer.Width * slider_zoom.Value;
            }
        }
    }
}
